
package com.controller.dao.page;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.beanutils.ConvertUtils;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.criterion.CriteriaSpecification;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import com.controller.common.FieldSearch;
import com.controller.common.FieldUtil;

public abstract class PageDaoHibernate<E> {

	@Resource
	protected HibernateTemplate hibernateTemplate;// 初始化模版

	protected final Class<E> clazz;

	protected static final String COUNT_STR = "select count(*) ";

	protected static final String COUNT_ID = "select count(id) ";

	@SuppressWarnings("unchecked")
	protected PageDaoHibernate() {

		clazz = (Class<E>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}

	/**
	 * 保存记录
	 * 
	 * @param obj
	 */
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = java.lang.RuntimeException.class)
	public final void saveOrUpdate(E obj) {

		if (obj == null)
			return;
		hibernateTemplate.saveOrUpdate(obj);
	}

	/**
	 * 根据ID删除记录
	 * 
	 * @param id
	 * @return
	 */
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = java.lang.RuntimeException.class)
	public final int deleteById(Integer id) {

		E entity = findById(id);
		if (entity == null)
			return 0;
		hibernateTemplate.delete(id);
		return 1;
	}

	/**
	 * 根据ID查询记录
	 * 
	 * @param id
	 * @return
	 */
	@Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
	public final E findById(Serializable id) {

		return (id == null) ? null : hibernateTemplate.get(clazz, id);
	}

	/**
	 * 更新记录
	 * 
	 * @param obj
	 */
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = java.lang.RuntimeException.class)
	public final void update(E obj) {

		if (obj == null)
			return;
		hibernateTemplate.update(obj);
	}

	/**
	 * 根据对象删除记录
	 * 
	 * @param obj
	 *            (删除对象)
	 */
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = java.lang.RuntimeException.class)
	public final void delete(E obj) {

		if (obj == null)
			return;
		hibernateTemplate.delete(obj);
	}

	/**
	 * 返回结果集
	 * 
	 * @param sql
	 *            (sql语句)
	 * @param values
	 *            (查询参数)
	 * @param pageNumber
	 *            (当前页数)
	 * @param pageSize
	 *            (每页条数)
	 * @return
	 */
	@Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
	protected final Page pageQuery(String sql, Map<String, Object> values, int pageNumber, int pageSize) {

		long totalCount = querySize(COUNT_STR + sql, values);// 查询总记录数
		Page page = Page.toPo(totalCount, pageNumber, pageSize);// 设置分页对象
		List<E> list = pageList(sql, values, page.getCurrentPage(), page.getPageSize());// 返回分页结果集
		page.setResult(list);// 设置结果集
		return page;
	}

	/**
	 * 查询分页记录数
	 * 
	 * @param sql
	 *            (sql语句)
	 * @param values
	 *            (查询参数)
	 * @param pageNumber
	 *            (当前页数)
	 * @param pageSize
	 *            (每页条数)
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
	public List<E> pageList(final String sql, final Map<String, Object> values, final int pageNumber, final int pageSize) {

		final int firstResult = pageNumber >= 1 ? pageSize * (pageNumber - 1) : 0;
		List<E> list = hibernateTemplate.executeFind(new HibernateCallback() {

			public Object doInHibernate(Session session) throws HibernateException, SQLException {

				Query query = session.createQuery(sql);
				if (values != null) {
					Set<String> keySet = values.keySet();
					for (String key : keySet) {
						Object obj = values.get(key);
						if (obj instanceof Collection<?>) {
							query.setParameterList(key, (Collection<?>) obj);
						}
						else if (obj instanceof Object[]) {
							query.setParameterList(key, (Object[]) obj);
						}
						else {
							query.setParameter(key, obj);//
						}
					}
				}
				query.setFirstResult(firstResult);//
				query.setMaxResults(pageSize);
				List<E> list = query.list();
				return list;
			}
		});
		return list;
	}

	/**
	 * 查询记录总数
	 * 
	 * @param sql
	 *            (sql语句)
	 * @param values
	 *            (查询参数)
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
	public List<E> pageCount(final String sql, final Map<String, Object> values) {

		List<E> list = hibernateTemplate.executeFind(new HibernateCallback() {

			public Object doInHibernate(Session session) throws HibernateException, SQLException {

				Query query = session.createQuery(sql);
				if (values != null) {
					Set<String> keySet = values.keySet();
					for (String key : keySet) {
						Object obj = values.get(key);
						if (obj instanceof Collection<?>) {
							query.setParameterList(key, (Collection<?>) obj);
						}
						else if (obj instanceof Object[]) {
							query.setParameterList(key, (Object[]) obj);
						}
						else {
							query.setParameter(key, obj);
						}
					}
				}
				return query.list();
			}
		});
		return list;
	}

	/**
	 * 自定义返回对象查询
	 * 
	 * @param sql
	 *            (sql语句)
	 * @param values
	 *            (查询条件参数)
	 * @param clzz
	 *            (返回自定义对象)
	 * @return
	 */
	@Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
	public List<E> queryCustomSql(final String sql, final Map<String, Object> values, final Class<E> clzz) {

		@SuppressWarnings({ "rawtypes", "unchecked" })
		List<E> list = hibernateTemplate.executeFind(new HibernateCallback() {

			public Object doInHibernate(Session session) throws HibernateException, SQLException {

				SQLQuery query = session.createSQLQuery(sql.toString());
				query.setResultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP);
				if (values != null) {
					Set<String> keySet = values.keySet();
					for (String key : keySet) {
						Object obj = values.get(key);
						if (obj instanceof Collection<?>) {
							query.setParameterList(key, (Collection<?>) obj);
						}
						else if (obj instanceof Object[]) {
							query.setParameterList(key, (Object[]) obj);
						}
						else {
							query.setParameter(key, obj);
						}
					}
				}
				// query.setFirstResult(1);
				// query.setMaxResults(10);
				@SuppressWarnings("unchecked")
				List<Map<String, Object>> list = (List<Map<String, Object>>) query.list();

				List<E> result = new ArrayList<E>();

				try {

					for (Map<String, Object> map : list) {
						E t = clzz.newInstance();
						for (Entry<String, Object> entry : map.entrySet()) {
							Field[] fields = clzz.getDeclaredFields();
							for (Field field : fields) {
								Object value = entry.getValue();
								if (entry.getKey().equals(field.getName())) {
									if (value != null) {
										if (field.getType().isEnum()) {
											Class clc = field.getType();
											value = Enum.valueOf(clc, value.toString());
										}
										else {
											value = ConvertUtils.convert(value.toString(), field.getType());
										}
									}
									field.setAccessible(true);
									field.set(t, value);
								}
							}
						}
						result.add(t);
					}
				}
				catch (Exception e) {
					e.printStackTrace();
				}

				return result;
			}
		});
		return list;

	}

	/**
	 * 查询记录总数
	 * 
	 * @param sql
	 *            (sql语句)
	 * @param values
	 *            (查询参数)
	 * @return
	 */
	@Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
	public final long querySize(String sql, Map<String, Object> values) {

		if (sql == null)
			return 0;
		List<?> list = pageCount(sql, values);// 查询记录总数
		if (list.size() < 1)
			throw new RuntimeException("sql:" + sql);
		Object obj = list.get(0);
		if (obj instanceof Long)
			return ((Long) obj);
		return 1;
	}

	/**
	 * 返回list结果集合 * @param sql (sql语句)
	 */
	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
	protected final List<E> queryList(String sql) {

		return hibernateTemplate.find(sql);
	}

	/**
	 * 初始化Sql要查询的字段
	 * 
	 * @param obj
	 */
	public String initSql(Object obj) {

		String orderFileds = "";// 排序字段

		String groupFileds = "";// 分组字段

		String havingFileds = "";// 聚合字段

		StringBuilder sql = new StringBuilder();
		// 获取该对象定义的sql查询语句
		FieldSearch sear = obj.getClass().getAnnotation(FieldSearch.class);
		if (sear != null) {
			if (StringUtils.hasText(sear.selectTabSql())) {
				// 初始化sql语句
				sql.append(sear.selectTabSql());
				// 通过反射获取泛型中类里面的注解
				List<FieldUtil> list = this.initReflect(obj);
				// 输出结果
				for (FieldUtil l : list) {
					String filedName = l.getFieldSearch().filedName();
					if (!StringUtils.hasText(l.getFieldSearch().filedName())) {
						filedName = l.getName();
					}
					// 拼接Sql语句
					if (StringUtils.hasText(l.getValue())) {
						sql.append(" and " + filedName + " " + l.getFieldSearch().searchType() + " " + l.getFieldSearch().startSymbol() + l.getValue() + l.getFieldSearch().endSymbol());
					}
					// 是否排序
					if (StringUtils.hasText(l.getFieldSearch().order())) {
						orderFileds += filedName + " " + l.getFieldSearch().order() + " ,";
					}
					// 是否分组
					if (l.getFieldSearch().group()) {
						groupFileds += filedName + " ,";
					}
					// 是否聚合
					if (StringUtils.hasText(l.getFieldSearch().hav())) {
						orderFileds = l.getFieldSearch().hav();
					}

				}
				// 增加分组条件
				if (StringUtils.hasText(groupFileds)) {
					sql.append(" group by " + groupFileds.substring(0, groupFileds.length() - 1));
				}
				// 增加聚合函数条件
				if (StringUtils.hasText(havingFileds)) {
					sql.append(" " + havingFileds);
				}
				// 增加排序条件
				if (StringUtils.hasText(orderFileds)) {
					sql.append(" order by " + orderFileds.substring(0, orderFileds.length() - 1));
				}
			}
		}
		return sql.toString();
	}

	/**
	 * 通过反射获取查询条件数据
	 * 
	 * @param obj
	 * @return
	 */
	public List<FieldUtil> initReflect(Object obj) {

		List<FieldUtil> list = new ArrayList<FieldUtil>();
		if (obj.getClass() != null) {
			// 取得该类所有自定义的对象
			Field[] fields = obj.getClass().getDeclaredFields();
			for (Field f : fields) {
				// 获取字段中包含fieldSearch的注解
				FieldSearch fieldSearch = f.getAnnotation(FieldSearch.class);
				if (fieldSearch != null) {
					FieldUtil sf = new FieldUtil(fieldSearch, f, obj);
					list.add(sf);
				}
			}
		}
		return list;

	}
}
